package org.rslai.tcedit.security;

import java.util.List;
import org.springframework.security.AccessDeniedException;
import org.springframework.security.Authentication;
import org.springframework.security.GrantedAuthority;
import org.springframework.security.GrantedAuthorityImpl;
import org.springframework.security.context.SecurityContextHolder;
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
import org.springframework.security.ui.WebAuthenticationDetails;
import org.springframework.security.userdetails.UserDetails;

public class SecurityUtil {

    public static String getCurrentUsername() {
        String username = getCurrentUsernameOrNull();
        if(username==null)
            throw new AccessDeniedException("Access denied.");
        return username;
    }

    public static String getCurrentUsernameOrNull() {
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        return _getUsernameFromAuth(auth);
    }

    public static boolean isAdminRole() {
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        return _hasRole(auth, "ROLE_ADMIN");
    }

    public static void assertUsername(String username) {
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        _assertUsername(auth, username);
    }

    public static void assertRoleOrUsername(String role, String username) {
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        if(!_hasRole(auth, role))
            _assertUsername(auth, username);
    }

    private static String _getUsernameFromAuth(Authentication auth) {
        if(auth==null)
            return null;
        if (auth.getPrincipal() instanceof UserDetails) {
            return ((UserDetails) auth.getPrincipal()).getUsername();
        }
        return auth.getPrincipal().toString();
    }

    private static boolean _hasRole(Authentication auth, String role) {
        if(auth==null)
            return false;
        GrantedAuthority[] gas = auth.getAuthorities();
        for(GrantedAuthority ga : gas) {
            if(ga.getAuthority().equals(role))
                return true;
        }
        return false;
    }

    private static void _assertUsername(Authentication auth, String username) {
        String s = _getUsernameFromAuth(auth);
        if(s==null || !s.equals(username))
            throw new AccessDeniedException("Access denied.");
    }

	/**
	 * 给用户设置新的权限 
	 * 这种方式不好但目前没有好的办法
	 */
	public static void refreshUserAuths(List<String> roleNames) {
		// 生成此用户所具有的角色信息
		int i = 0;
		GrantedAuthority[] newAuthorities = new GrantedAuthority[roleNames.size()];
		for (String roleName : roleNames) {
			newAuthorities[i] = new GrantedAuthorityImpl(roleName);
			i = i + 1;
		}

		Authentication auth = SecurityContextHolder.getContext().getAuthentication(); // 得到当前 Authentication

		// 给 CustomUserDetails 设置新的 Authorities
		Object principal = auth.getPrincipal();
		if (principal instanceof CustomUserDetails) {
			((CustomUserDetails) principal).setAuthorities(newAuthorities);
		}

		// 创建新的 Authentication
		UsernamePasswordAuthenticationToken newAuth = new UsernamePasswordAuthenticationToken(principal, auth.getCredentials(), newAuthorities);
		// 设置新 Authentication 的 details
		Object details = auth.getDetails();
		if (details instanceof WebAuthenticationDetails) {
			newAuth.setDetails((WebAuthenticationDetails) details);
		}

		// 将新 Authentication 放回 SecurityContext
		SecurityContextHolder.getContext().setAuthentication(newAuth);
	}

}
